﻿using Moki;
using Moki.Tests.Model;
using NUnit.Framework;
using System;

namespace Moki.Specification
{
    [TestFixture]
    public class EventsSpec
    {
        [TearDown]
        public void TearDown()
        {
            Mock.CleanUp();
        }

        [Test]
        public void Should_subscribe_and_call_when_event_raised()
        {
            IObserver obs1 = Mock.Create<IObserver>();
            IObserver obs2 = Mock.Create<IObserver>();

            Observable observable = new Observable();
            observable.NotifyHandler += obs1.Notify;
            observable.NotifyHandler += obs2.Notify;

            observable.NotifyObservers();

            Mock.VerifyCalledWithAnyArgs(() => obs1.Notify(new object(), new EventArgs()));
            Mock.VerifyCalledWithAnyArgs(() => obs2.Notify(new object(), new EventArgs())); 

        }

        [Test]
        public void Should_subscribe_to_mock_event()
        {
            var obs = Mock.Create<IObserver>();
            var obserable = Mock.Create<IObservable>();

            obserable.NotifyHandler += obs.Notify;
        }

        [Test]
        public void Should_raise_event()
        {
            IGPS gps = Mock.Create<IGPS>();
            var screen1 = Mock.Create<Screen>();
            var screen2 = Mock.Create<Screen>();

            gps.PositionChanged += screen1.UpdatePosition;
            gps.PositionChanged += screen2.UpdatePosition;

            Mock.RaiseEvent(() => gps.PositionChanged += null, EventArgs.Empty);

            Mock.VerifyCalled(() => screen1.UpdatePosition(Arg.Any<object>(), EventArgs.Empty));
            Mock.VerifyCalled(() => screen2.UpdatePosition(Arg.Any<object>(), Arg.Any<EventArgs>()));

        }

        [Test]
        public void Should_raise_event_after_method_call()
        {
            IGPS gps = Mock.Create<IGPS>();
            var screen1 = Mock.Create<Screen>();
            var screen2 = Mock.Create<Screen>();

            gps.PositionChanged += screen1.UpdatePosition;
            gps.PositionChanged += screen2.UpdatePosition;

            Mock.WhenCalled(() => gps.MoveTo(1, 2))
                .Raises(() => gps.PositionChanged += null, new EventArgs());

            gps.MoveTo(1, 2);

            Mock.VerifyCalledWithAnyArgs(() => screen1.UpdatePosition(Arg.Any<object>(), EventArgs.Empty));
            Mock.VerifyCalledWithAnyArgs(() => screen2.UpdatePosition(Arg.Any<object>(), Arg.Any<EventArgs>()));
        }
    }
}
